package com.xperblueray.stepbystep.service.impl;

import com.xperblueray.stepbystep.dao.SysDictDao;
import com.xperblueray.stepbystep.exception.BusinessException;
import com.xperblueray.stepbystep.model.SysDict;
import com.xperblueray.stepbystep.repository.SysDictRepository;
import com.xperblueray.stepbystep.service.SysDictService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Future;

import static com.xperblueray.stepbystep.constant.Constant.ALL_ATTR;

@Transactional
@Service
public class SysDictServiceImpl implements SysDictService {
    Logger logger = LogManager.getLogger(this.getClass());

    @Resource
    SysDictRepository sysDictRepository;

    @Resource
    RedisTemplate redisTemplate;

    @Resource
    SysDictDao sysDictDao;

    @Override
    public SysDict findById(String id) {
        List<SysDict> sysDicts = redisTemplate.opsForList().range(ALL_ATTR, 0, -1);

        Optional<SysDict> any = sysDicts.stream().filter(e -> id.equals(e.getId())).findAny();
        if(any.isPresent()) {
            return any.get();
        } else {
            Optional<SysDict> temp = sysDictRepository.findById(id);
            if(temp.isPresent()) {
                redisTemplate.opsForList().leftPush(ALL_ATTR, temp.get());
            }
            return temp.get();
        }
    }

    private boolean listContiansById(List<SysDict> list, String id) {
        return list.stream().filter(e -> id.equals(e.getId())).findAny().isPresent();
    }
    @Override
    public List<SysDict> findAll() {
        try {
            long start = System.currentTimeMillis();
            List<SysDict> dicts =  sysDictRepository.findAll();

            for (int i = 0; i < 100; i++) {
                Thread.sleep(10);
            }
            long end = System.currentTimeMillis();
            logger.info("耗时：" + (end - start) + "毫秒");
            return dicts;
        } catch (Exception e) {
            logger.error(e.getMessage());
            return null;
        }

    }

    @Override
    @Async
    public Future<List<SysDict>> findSyncAll() {
        try {
            long start = System.currentTimeMillis();
            List<SysDict> dicts =  sysDictRepository.findAll();
            for (int i = 0; i < 100; i++) {
                Thread.sleep(10);

            }
            long end = System.currentTimeMillis();
            logger.info("耗时：" + (end - start) + "毫秒");
            return new AsyncResult<>(dicts);
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new AsyncResult<List<SysDict>>(null);
        }

    }

    @Transactional
    @Override
    public SysDict save(SysDict sysDict) {
        SysDict sysDict1 = sysDictRepository.save(sysDict);
        // 出现空指针异常
//        String error = null;
//        error.split("/");
        return sysDict1;
    }

    @Override
    public void delete(String id) {
        logger.info("id:" + id + "属性被删除");
        sysDictRepository.deleteById(id);
    }

    @Override
    public Page<SysDict> findAll(Pageable pageable) {
        return sysDictRepository.findAll(pageable);
    }

    @Override
    public List<SysDict> findByFilename(String filename) {

        return sysDictRepository.findByName(filename);
    }

    @Override
    public List<SysDict> findByValue(String value) {
        return sysDictRepository.findByValue(value);
    }

    @Override
    public List<SysDict> findByFilenameLike(String filename) {
        return sysDictRepository.findByNameLike(filename);
    }

    @Override
    public List<SysDict> findByFileIdIn(Collection<String> ids) {
        return sysDictRepository.findByIdIn(ids);
    }

    @Override
    public SysDict findByNameAndValue(String name, String value) {
        SysDict sysDict = sysDictDao.findByNameAndValue(name, value);
        logger.info(sysDict);
        return sysDict;
    }

    @Override
    // value属性表示当出现哪些异常的时候触发重试，maxAttempts表示最大重试次数为3，delay表示延迟时间，multiplier表示上一次延迟时间是这一次的倍数
    @Retryable(value = {BusinessException.class}, maxAttempts = 3, backoff = @Backoff(delay = 5000, multiplier = 2))
    public SysDict findByNameAndType(String name, String type) {
        try {
            logger.info("[findByNameAndType] 方法失败重试了！");
            throw new BusinessException();
        } catch (Exception e) {
//            logger.error("[findByNameAndType] 执行失败！", e);
            throw e;
        }
    }
}
